package com.google.code.jbauble.mvc.support;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javassist.NotFoundException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.code.jbauble.mvc.DefaultConfiguration;
import com.google.code.jbauble.mvc.Result;
import com.google.code.jbauble.mvc.annotations.Layout;
import com.google.code.jbauble.mvc.annotations.RequestMapping;

public class ActionMapper {
	private String controllerUrl;
	private Object controller;
	private String methodUrl;
	private Method method;
	private DefaultConfiguration config;
	private int httpMethod;
	private boolean isRegex;
	
	private String defaultViewUrl;
	private String extension = null;
	
	private String mapUrl;
	private Pattern urlPattern = null;
	private ActionParameter methodParameter = null;
	
	private int mapperType = 0;
	
	private boolean isLayout = false;
	private String layout = null;

	public ActionMapper(String controllerUrl, Object controller, boolean isRegex, String methodUrl, Method method, int httpMethod, DefaultConfiguration config) {
		this.controllerUrl = controllerUrl;
		this.controller = controller;
		this.methodUrl = methodUrl;
		this.method = method;
		this.httpMethod = httpMethod;
		this.config = config;
		extension = "." + config.getProperty(DefaultConfiguration.MVC_VIEW_EXTENSION);
		
		mapUrl = UrlHelper.mergeUrl(controllerUrl, methodUrl);
		this.isRegex = isRegex;
		if (isRegex) {
			urlPattern = Pattern.compile(mapUrl, Pattern.CASE_INSENSITIVE);
		}
		defaultViewUrl = getDefaultViewUrl(UrlHelper.getControllerSimpleName(controller.getClass().getSimpleName()),
				method.getName());
		initLayoutConfig();
		try {
			methodParameter = createMethodParameter(controller, method, Integer.valueOf(config.getProperty(DefaultConfiguration.MVC_UPLOAD_MAX)));
		} catch (NotFoundException e) {
			mapperType = 1;
			e.printStackTrace();
		}
	}

	private final String LAYOUT_PREXF = "layout/";
	
	private void initLayoutConfig() {
		String name = config.getProperty(DefaultConfiguration.MVC_DEFAULT_LAYOUT);
		Layout la = method.getAnnotation(Layout.class);
		if (la == null || la.type() == Layout.LAYOUT) {
			if (la != null && la.name() != null && !la.name().equals("")) {
				isLayout = true;
				layout = LAYOUT_PREXF + la.name();
			}
			else if (name != null && !name.equals("")) {
				isLayout = true;
				layout = LAYOUT_PREXF + name;
			}
			else {
				isLayout = false;
			}
		}
		else {
			isLayout = false;
		}
	}

	private String getDefaultViewUrl(String cu, String mu) {
		return cu + "/" + mu + extension;
	}
	
	/**
	 * 从控制类型得到名称
	 * @param c 控制类
	 * @return 控制类url名称
	 */
	private String getControllerUrl(Class c) {
		String controllerUrl = null;
		Annotation a = c.getAnnotation(RequestMapping.class);
		RequestMapping ca = (RequestMapping)a;
		if (ca != null) {
			controllerUrl = ca.path();
		}
		else {
			controllerUrl = UrlHelper.getControllerSimpleName(c.getSimpleName());
		}
		return controllerUrl;
	}

	private ActionParameter createMethodParameter(Object c,Method m, int max) throws NotFoundException {
		return new ActionParameter(c, m, max);
	}
	
	public boolean isMatchUrl(int method, String url) {
		return (httpMethod == UrlHelper.HTTP_ALL || httpMethod == method) && url.equals(mapUrl);
	}
	
	public Result execute(HttpServletRequest request, HttpServletResponse response) 
			throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
		Object[] params = null;
		if (isRegex) {
			params = methodParameter.getParameters(regexParameters, request, response);
		}
		else {
			params = methodParameter.getParameters(null, request, response);
		}
		Result r = (Result)method.invoke(controller, params);
		if (r == null)
			return r;
		
		if (r.getType() == Result.RENDER) {
			if (r.getUrl() == null) {
				r.setUrl(defaultViewUrl);
			}
			else if (!r.getUrl().endsWith(extension)) {
				r.setUrl(r.getUrl() +  extension);
			}
		}
		return r;
	}

	private String[] regexParameters = null;
	
	public boolean isMatchRegexUrl(int method, String url) {
		if (httpMethod != UrlHelper.HTTP_ALL && httpMethod == method)
			return false;
		Matcher m = urlPattern.matcher(url);
		if (!m.find())
			return false;
		int count = m.groupCount();
		regexParameters = new String[count];
		for (int i=0; i<count; i++) {
			regexParameters[i] = m.group(i + 1);
		}
		return true;
	}

	public boolean isLayout() {
		return isLayout;
	}

	public String getLayout() {
		// TODO Auto-generated method stub
		return layout;
	}
}
